这一章名为变量和基本类型,个人觉得需要重点关注的是引用与指针,以及const相关的知识。
变量的定义和声明
声明: 使得名字为程序所知,
定义:负责创建与名字相关的实体。
如果想要声明一个变量而非定义它,就需要在变量名前加上关键字extern。
1 | eg. extern int i; //声明i而非定义 |
然而,如果给extern标记的变量赋予了初始值,则进行了定义。
变量只能被定义一次,但是可以被多次声明
复合类型
引用和指针都是c++的复合类型。他们的相似和区别如下:
相同 | 不同 | |
---|---|---|
引用 | 实现了对某个对象的间接访问 一般情况引用类型需要和绑定的对象严格匹配 |
1. 引用在定义时就要进行和对象的绑定,一经绑定无法修改 2. 引用本身不是一个对象,仅仅是一个别名,没有实际地址 3. 引用只能绑定在某个对象上,不能绑定在字面值或者计算结果 |
指针 | 实现了对某个对象的间接访问 一般情况引用类型需要和绑定的对象严格匹配 |
1. 指针本身就是一个对象,允许对指针赋值访问 2. 指针无需在定义时赋初值,而且在其生命周期,可以多次指向不同对象 3. 指针存放的是对象地址,所以赋值时要用取址符&获取对象地址 4. 使用指针时,需要使用解引用符*来访问对象 |
注: 可以有指向指针的引用,不能有指向引用的指针
1 | int i = 42; |
空指针:nullptr (c++11新标准引入) 等同于初始化为字面值0。
void* 指针: 一种特殊的指针类型,可以用于存放任意对象的地址。我们可以用void*指针进行指针比较、作函数输入或输出,或者赋值给别的void*指针,但是我们不能直接操作它所指向的对象。
const限定符
const对象一般情况下仅在文件内有效。当多个文件中出现多个const,则说明是在多个文件中分别定义了不同的对象。
如果想要在多个文件中声明或使用某个const对象,那就需要在定义和声明时都加上extern关键字。
const的引用
前面提到引用必须严格和绑定的对象进行匹配,int配int,double配double,但是在const中,针对const的引用是允许用任意表达式作为初始值的,只要其结果可以转换为引用的类型就可以。
1 | eg. |
当然此时对ri是无法进行赋值操作的,而且此时 编译器中实质发生的是这样的过程:
1 | double dval = 3.14; |
引入了临时量这一概念之后,就很好理解“对const的引用可能引用一个并非const对象”的概念了。
1 | int i = 42; |
指针与const
普通指针类型无法指向常量。只有指向常量的指针才可以指向常量类型。指向常量类型的指针写作:const 数据类型 *ptr
。
前面同样提到指针类型必须和它指向的对象的类型一致,但是指向常量的指针,也是可以指向一个非常量的对象的。
1 | eg. |
常量指针(const pointer):const允许把指针本身定为常量。常量指针必须初始化, 一但初始化完成,指针就和它所指向的地址绑定了。但是指针指向的变量本身是可以改变的,换言之如果指向的是变量而不是常量,我们仍然可以使用ptr进行访问或修改。常量指针写作:``数据类型 const ptr``;
常量指针(顶层const) | 指向常量的指针(底层const) | 指向常量的常量指针 (右边的const是顶层const 左边的const是底层const) |
---|---|---|
指针对象是一个常量 | 指针指向的对象是一个常量 | 两者都是常量 |
可以通过解引用符*修改指向的变量 | 无法通过解引用符*修改指向的变量 | 无法通过解引用符*修改指向的变量 |
无法指向其他的对象 | 可以指向其他的对象 | 无法指向其他的对象 |
声明时必须初始化 | 声明时不必定义 | 声明时必须初始化 |
顶层const和底层const
底层const | 顶层const | |
---|---|---|
定义 | 指针和引用的复合类型的基本类型部分是常量 | 任意的对象是常量 |
拷贝操作 | 拷入拷出的对象必须都是相同的底层const,或者可以相互转换(非常量可以转为常量,反之不行) | 不受影响 |
底层const和顶层const的实质理解是这样的:
对于一般对象,只存在顶层const
对于指针,由于指针包含了本身这个对象和它所指向的对象两个对象,所以指针本身的const称之为顶层const,指针指向的对象的const称之为底层const
对于引用,引用本身不是对象,所以只存在底层const
constexpr和常量表达式
常量表达式指的是在编译过程就能得到计算结果的表达式
声明为constexpr的变量一定是一个常量,而且必须用常量表达式初始化
一个constexpr指针的初始值必须为nullptr或者0,或者某个存储在固定地址的对象
指针和constexpr
1 | constexpr int *q = nullptr // q是一个指向整数的常量指针,等同于 int *const q = nullptr |
constexpr可以把它所定义的对象置为顶层const。同时,constexpr指针既可以指向常量也可以指向非常量。但是当它指向一个变量名时,它的定义必须在函数体外
1 | int j = 0; |
处理类型
类型别名
指针、常量和类型别名
1 | eg. |
总之不能直接将typedef带入进行理解。
auto类型说明符和decltype类型指示符
c++11新标准引入的新的类型说明符auto和类型指示符decltype。
- auto 让编译器通过初始值来推算变量的类型
- auto定义的变量必须具有初始值
- auto能在一条语句中声明多个变量,但是该语句中所有变量的初始基本数据类型必须一致。
- decltype 编译器分析表达式并得到它的类型,但是不计算表达式的值
- decltype如果使用的是一个不加括号的变量,则得到的结果就是该变量的类型
- decltype如果使用的是一个加括号的变量 ,则编译器会把它当作表达式,得到的结果是引用类型
auto | decltype | |
---|---|---|
相同 | 都可以通过编译器获得变量类型 | 都可以通过编译器获得变量类型 |
不同 | 1. 跟引用相关时,auto采用的是引用对象的值 2. 在处理顶层const时,auto会自动忽略掉顶层const,只保留底层const 3. 跟解引用*相关时,auto采用的是对对象地址进行解引用后的值 |
1. 跟引用相关时,decltype采用的是对象的引用 2. 在处理顶层const时,decltype会保留顶层const 3. 跟解引用相关时,decltype采用的是对对象的引用 |
原文链接: https://zijian.wang/2020/11/04/《C++ Primer 第五版》阅读过程查漏补缺 Chapter2/
版权声明: 转载请注明出处.